package greetings

import "fmt"

func ClosePackage() func() int {

	var i = 10
	//这里演示闭包的逻辑，把方法b返回值之后
	//b可以持续访问i的值
	b := func() int {
		i++
		fmt.Println("演示闭包逻辑：", i)
		return i
	}
	//这里返回一个方法
	return b
}

func Factorial(i int) int {
	if i <= 1 {
		return 1
	}
	return i * Factorial(i-1)
}

func ClosePackageAndDefer() {
	var whatever [5]struct{}
	for i := range whatever {
		defer func() { fmt.Println(i) }()
	}
}

//一个容易出错的例子
type Test struct {
	name string
}

func (t *Test) Close() {
	fmt.Println(t.name, " closed")
}
func ErrorDeferDemo() {
	ts := []Test{{"a"}, {"b"}, {"c"}}
	for _, t := range ts {
		defer t.Close()
	}
}

func closeThis(t Test) {
	t.Close()
}

// 正确的做法有以下几种
// 01 包装成函数
func ErrorDeferDemo2() {
	ts := []Test{{"a"}, {"b"}, {"c"}}
	for _, t := range ts {
		//临时保存这个引用
		defer closeThis(t)
	}

	// 02 保存临时引用
	for _, t := range ts {
		//临时保存这个引用
		t1 := t
		defer t1.Close()
	}

	defer fmt.Println("first defer")
	defer fmt.Println("second defer")
	defer fmt.Println("third defer")
}
